#include <avr/io.h>
#include <string.h> 
#include <ctype.h>

#include "serial.h"
#include "uart.h"
#include "maintask.h"


#define BAUDX	 8		// Baud rate divisor.
#define BAUD(A) ((F_CPU/BAUDX/(A))-1)

#define SERIAL_TIME_OUT 		100
#define SERIAL_OUTPUT_TIME_OUT 	10
static TimerControlBlock sSerialTimer;
//unsigned char cECHO_ON = TRUE;

MessageQueue 	sSerialQueue;           		// The message queue itself
sSSerialMessage sSerialMessage;

AVRX_DECL_FIFO(SerialOutBuf, 64);

int doStringCompare(char * pS1,char * pS2,char cLeng)
{
	do
	{	
		if( (*pS1 != ' ') || (*pS2 == ' ') )
		{			
			if( tolower(*pS1++) != tolower(*pS2++) )
			{
				return FALSE;
			} 
			
			if (*pS2 == '\0')
			{
				if( (*pS1 == ' ') || (*pS1 == '\0') )
					return TRUE;
				else
					return FALSE;
			}
			
			cLeng--;
		}
		else
			pS1++;			
	}
	while(cLeng != 0);
	
	return TRUE;
}

int IsStrNumber(char cStr)
{
	if( cStr >= '0' && cStr <= '9' )
	{
		return TRUE;
	}
	return FALSE;
}

int IsTimeNumer(char *pTime)
{
	unsigned char ucH = (*(pTime + 0)*10) + *(pTime + 1);	
	unsigned char ucM = (*(pTime + 2) *10)  + *(pTime + 3);	

	if( (ucH < 24) && (ucM < 60) )
		return TRUE;
	else
		return FALSE;	
}

int IsTimeformat(char *pStr, char *pTime)
{
	unsigned char ucGetStrCount = 0;
	unsigned char ucStrCount = 0;
	int 		  iRunning = TRUE;
	int           iStatus = FALSE;
	
	do
	{
		if( *pStr != ' ' )
		{
			switch( ucStrCount )
			{
				case 0:
				case 1:
				case 3:
				case 4:
					if( IsStrNumber(*pStr) == TRUE )
					{
						*(pTime + ucGetStrCount) = *pStr - '0';
						ucGetStrCount++;
					}					
					else
					{
						iRunning = FALSE;
					}
					break;
				case 2:
					if( *pStr != ':' )
					{
						iRunning = FALSE;
					}					
					break;
				default:
					if( ucGetStrCount == 4 && ( *pStr == '\0' || *pStr == ' ') )
					{
						iStatus  = TRUE;
					}					
					iRunning = FALSE;					
					break;					
			}
			ucStrCount++;			
		}
		pStr++;
	}
	while(iRunning == TRUE);
			
	return iStatus;
}


sSMainData sMainData;
void sendMainMessage(char cAct, char * pPtr)
{
	sMainData.m_act = cAct;
	sMainData.m_ptr = (char *)pPtr;
	sMainMessage.m_ptr = &sMainData;
	AvrXSendMessage(&sMainQueue, &sMainMessage.m_mcb);
	AvrXWaitMessageAck(&sMainMessage.m_mcb);
}

const char output_error[] = "ERR ";
void doOutputError( char cErrCode )
{
	unsigned char cLen;
	
	for( cLen=0; cLen<strlen(output_error); cLen++ )
	{
		if(AvrXPutFifo(SerialOutBuf, output_error[cLen]) == FIFO_ERR)
		{
			return;
		}
	}	
	
	AvrXPutFifo(SerialOutBuf, '0' +cErrCode );	
	AvrXPutFifo(SerialOutBuf, '\r' );	
	AvrXPutFifo(SerialOutBuf, '\n' );	
	
}

const char str_act[] 		= "act";
const char str_time[] 		= "time";
const char str_toggle[] 	= "toggle";
const char str_all[] 		= "all";
const char str_on[] 		= "on";
const char str_off[] 		= "off";
const char str_disable[] 	= "disable";

static char cDataBuf[4] = {0,0,0,0};
void doSerialCommand(char * pCmd)
{
	char * pcPost;

	if( doStringCompare(pCmd, (char*)&str_act, sizeof(str_act)) == TRUE )
	{
		pcPost = pCmd + strlen(str_act); 
		if( *pcPost == ' ' )
		{
			pcPost++;
			if( IsStrNumber(*pcPost) == TRUE )
			{
				if( IsStrNumber(*(pcPost+1)) == TRUE )
				{
					sendMainMessage(((*pcPost - '0')*10) + (*(pcPost+1) - '0'),NULL);
				}
				else
					sendMainMessage(*pcPost - '0',NULL);
			}
			else
				doOutputError(3);
		}
		else
			doOutputError(4);	
	}
	else if( doStringCompare(pCmd, (char*)&str_time, sizeof(str_time)) == TRUE )
	{
		pcPost = pCmd + strlen(str_time); 
		if( doStringCompare(pcPost, (char*)&str_all, strlen(str_all)) == TRUE )		
			sendMainMessage(10,NULL);
		else if( doStringCompare(pcPost, (char*)&str_on, strlen(str_on)) == TRUE )		
		{
			pcPost = pCmd + strlen(str_time) + strlen(" ") + strlen(str_on); 
			if( doStringCompare(pcPost, (char*)&str_disable, strlen(str_disable)) == TRUE )					
				sendMainMessage(17,NULL);					
			else if( IsTimeformat(pcPost,(char *)&cDataBuf) == TRUE )
			{
				if( IsTimeNumer((char *)&cDataBuf) == TRUE )
					sendMainMessage(15,(char *)&cDataBuf);
				else
					doOutputError(1);					
			}
			else
				sendMainMessage(12,NULL);							
		}
		else if( doStringCompare(pcPost, (char*)&str_off, strlen(str_off)) == TRUE )		
		{
			pcPost = pCmd + strlen(str_time) + strlen(" ") + strlen(str_off); 
			if( doStringCompare(pcPost, (char*)&str_disable, strlen(str_disable)) == TRUE )					
				sendMainMessage(17,NULL);								
			else if( IsTimeformat(pcPost,(char *)&cDataBuf) == TRUE )
			{
				if( IsTimeNumer((char *)&cDataBuf) == TRUE )
					sendMainMessage(16,(char *)&cDataBuf);
				else
					doOutputError(1);							
			}
			else
				sendMainMessage(13,NULL);
		}
		else if( *pcPost == ' ' )
		{
			if( IsTimeformat(pcPost,(char *)&cDataBuf) == TRUE )
			{
				if( IsTimeNumer((char *)&cDataBuf) == TRUE )
					sendMainMessage(14,(char *)&cDataBuf);
				else
					doOutputError(1);					
			}
			else
			{
				pcPost++;
				if( *pcPost == '+' )
				{
					pcPost++;
					if( IsStrNumber(*pcPost) == TRUE && *pcPost < '4')
					{
						sendMainMessage(20 + *pcPost - '0',NULL);
					}
					else					
						doOutputError(2);					
				}
				else if( *pcPost == '-' )
				{
					pcPost++;
					if( IsStrNumber(*pcPost) == TRUE && *pcPost < '4')
					{
						sendMainMessage(25 + *pcPost - '0',NULL);
					}									
					else					
						doOutputError(2);							
				}
				else
					sendMainMessage(11,NULL);
			}
		}
		else if( *pcPost == '\0' )		
			sendMainMessage(11,NULL);
		else
			doOutputError(0);			
	}
	else if( doStringCompare(pCmd, (char*)&str_toggle, strlen(str_toggle)) == TRUE )
	{		
		pcPost = pCmd + strlen(str_toggle);
		if( doStringCompare(pcPost, "0", strlen("0")) == TRUE )		
			sendMainMessage(90,NULL);
		else if( doStringCompare(pcPost, "1", strlen("1")) == TRUE )		
			sendMainMessage(91,NULL);
		else if( doStringCompare(pcPost, "2", strlen("2")) == TRUE )		
			sendMainMessage(92,NULL);
		else if( doStringCompare(pcPost, "3", strlen("3")) == TRUE )		
			sendMainMessage(93,NULL);
		else if( doStringCompare(pcPost, "4", strlen("4")) == TRUE )		
			sendMainMessage(94,NULL);
		else if( doStringCompare(pcPost, (char*)&str_off, strlen(str_off)) == TRUE )		
			sendMainMessage(95,NULL);
		else if( doStringCompare(pcPost, (char*)&str_all, strlen(str_all)) == TRUE )
			sendMainMessage(96,NULL);
		else
			doOutputError(0);
	}
	else
		doOutputError(0);
	
}

void doSerialMessage( psSSerialData p )
{
	char cLeng;	
	for(cLeng=0;cLeng < p->m_leng;cLeng++)
	{	
		if(AvrXPutFifo(SerialOutBuf, *p->m_ptr++) == FIFO_ERR)
		{
			break;
		}		
	}
}

char cInputBufferCmd[20];
unsigned char cInputPost = 0;
void doResetInputCmdBuffer( void )
{
	memset((void *)&cInputBufferCmd,0,sizeof(cInputBufferCmd));
	cInputPost = 0;
}

int doAppendInputCmdBuffer(char c)
{
	if(cInputPost < sizeof(cInputBufferCmd))
	{
		cInputBufferCmd[cInputPost++] = c;		
		return TRUE;
	}
	return FALSE;
}

char * GetInputBuffer( void )
{
	return (char *)&cInputBufferCmd;
}

AVRX_GCC_TASKDEF(SerialTask, 35, 2)
{
	char c;
	psSSerialMessage pMsg;
	unsigned char time_out = SERIAL_TIME_OUT;
	
	sSerialTimer.semaphore = SEM_PEND;	// Need to initialize stack variables...	
	
	//InitUART(BAUD(9600));
	InitUART(BAUD(115200));	// Note: this only works with 12mhz or baud rate crystal
	//InitUART(BAUD(38400));	// Note: this only works with 12mhz or baud rate crystal
	stdin = stdout = &serial;

	doResetInputCmdBuffer();

	AVRX_INIT_FIFO(SerialOutBuf);

	//printf("\r\Serial ini\r\n");
	
	AvrXDelay(&sSerialTimer, 1000); //100 milisec
	
	AvrXStartTimerMessage((pTimerMessageBlock)&sSerialTimer, SERIAL_TIME_OUT, &sSerialQueue); //100 10 milliseconds
	
	while(1)
	{
		time_out = SERIAL_TIME_OUT;	
		pMsg = (psSSerialMessage)AvrXWaitMessage(&sSerialQueue);
		
		if( pMsg == &sSerialMessage )
		{
			doSerialMessage( pMsg->m_ptr );	 
			AvrXAckMessage( &pMsg->m_mcb );
		}
		else if((pTimerMessageBlock)pMsg == (pTimerMessageBlock)&sSerialTimer)
		{
			if( UARTBuffEmpty() == FALSE )
			{
				if ((c = getchar()) >= 0)
				{
					if (c == 0x0D)
					{
						printf("\r\n");
						doAppendInputCmdBuffer('\0');
						doSerialCommand( (char *)GetInputBuffer() );
						doResetInputCmdBuffer();				
					}
					else
					{
						putchar(c);
						doAppendInputCmdBuffer(c);
					}
				}                
			}
			else if(AvrXPeekFifo(SerialOutBuf) != FIFO_ERR)
			{
				putchar( AvrXPullFifo(SerialOutBuf) );
				time_out = SERIAL_OUTPUT_TIME_OUT;
			}			
			AvrXStartTimerMessage((pTimerMessageBlock)&sSerialTimer, time_out, &sSerialQueue); 
		}
		else
		{
			AvrXHalt();
		}
		
		
		
	}
}
